package com.ls.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ls.config.satoken.SaTokenUtilPy;
import com.ls.controller.weixin.model.PayModel;
import com.ls.entity.Customer;
import com.ls.entity.OrderRecord;
import com.ls.mapper.OrderRecordMapper;
import com.ls.service.ICustomerService;
import com.ls.service.IOrderRecordService;
import com.ls.service.IProductService;
import com.ls.service.IWeixinPayService;
import com.ls.utils.ResultData;
import com.ls.utils.UUIDUtils;
import com.ls.utils.pay.WXAPPPayHelper;
import com.ls.utils.weixin.WXPayUtility;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.cipher.Signer;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RSACombinedNotificationConfig;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.app.AppService;
import com.wechat.pay.java.service.payments.app.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.QueryByOutRefundNoRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.cert.Extension;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static com.ls.constant.SystemConstants.*;

/**
 * <p>
 * 微信支付 服务实现类
 * </p>
 *
 * @author pengyu
 * @since 2024-10-12
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WeixinPayServiceImpl extends ServiceImpl<OrderRecordMapper, OrderRecord> implements IWeixinPayService {
    private AppService service;
    private RefundService refundService;
    private final ICustomerService customerService;
    private final IOrderRecordService orderRecordService;
    private Signer signer;
    @Value("${wxpay.appid}")
    private String appid;
    @Value("${wxpay.mchid}")
    private String mchid;
    @Value("${wxpay.apiV3Key}")
    private String apiV3Key;
    @Value("${wxpay.publicKeyId}")
    private String publicKeyId;
    @Value("${wxpay.certPath}")
    private String certPath;
    @Value("${wxpay.privateKeyPath}")
    private String privateKeyPath;
    @Value("${wxpay.publicKeyPath}")
    private String publicKeyPath;
    @Value("${wxpay.merchantPath}")
    private String merchantPath;
    @Value("${wxpay.merchantSerialNumber}")
    private String merchantSerialNumber;
    @Value("${wxpay.notifyUrl}")
    private String notifyUrl;
    @Value("${pay.expire.time}")
    private Integer time;
    @Value("${pay.polling.count}")
    private Integer count;
    /*
     *预支付
     */
    @Override
    public ResultData advancePay(String orderNum, BigDecimal money, Integer productType) {
            PrepayRequest request = new PrepayRequest();
            request.setAppid(appid);
            request.setMchid(mchid);
            request.setDescription(productType==PRODUCT_TYPE_MEMBER?"乐信通会员服务":productType==PRODUCT_TYPE_SMS?"乐信通短信套餐":"乐信通加量包");
            request.setOutTradeNo(orderNum);
            request.setTimeExpire(ZonedDateTime.now(ZoneOffset.of("+8")).plusMinutes(time).format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX")));
            request.setNotifyUrl(notifyUrl);
            Amount orderAmount = new Amount();
            // 修改后的金额计算方式
            long amountInCents = money.multiply(new BigDecimal(100))
                    .setScale(0, RoundingMode.HALF_UP)
                    .longValue();
            orderAmount.setTotal((int) amountInCents);
            request.setAmount(orderAmount);
            log.info("微信下单成功：{}", JSON.toJSONString(request));
            try {
                // 调用微信下单接口，获取预支付ID==》response.getPrepayId()
                PrepayResponse response = service.prepay(request);
                log.info("微信下单成功222222222：{}", JSON.toJSONString(response));
                String nonceStr = UUIDUtils.generate();
                String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
                //生成微信签名
                String message = request.getAppid() + "\n" + timestamp + "\n" + nonceStr + "\n" + response.getPrepayId() + "\n";
                log.info("微信签名：{}", message);
                String sign = signer.sign(message).getSign();
                //签名生成结束
                log.info("微信签名222222222：{}", sign);
                PayModel payModel = new PayModel();
                payModel.setAppId(appid);
                payModel.setPartnerId(mchid);
                payModel.setPrepayId(response.getPrepayId());
                payModel.setPackageValue("Sign=WechatPay");
                //获取当前时间戳
                payModel.setTimeStamp(timestamp);
                payModel.setNonceStr(nonceStr);
                payModel.setSign(sign);
                return ResultData.successData(payModel);
            } catch (Exception e) {
                log.info("微信下单异常：{}", e.getMessage());
                throw new RuntimeException(e);
            }

    }
    /*
     *支付结果异步回调
     */
    @Override
    public String getPayType(HttpServletRequest request) {
        //验签时间戳
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        //验签的随机串
        String nonce = request.getHeader("Wechatpay-Nonce");
        //验签的签名
        String signature = request.getHeader("Wechatpay-Signature");
        //微信支付公钥id
        String serial = request.getHeader("Wechatpay-Serial");
        StringBuilder body = new StringBuilder();
        log.info("微信支付结果异步回调查看请求头数据: {}", body.toString());

        try {
            String str = null;
            BufferedReader br = request.getReader();
            while ((str = br.readLine()) != null) {
                body.append(str);
            }
        } catch (Exception e) {
            log.error("支付回调处理失败", e);
            throw new RuntimeException("支付回调处理失败");
        }
        //创建通知参数
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serial)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .body(body.toString())
                .build();
        //创建通知配置
        NotificationConfig config = new RSACombinedNotificationConfig.Builder()
                .merchantId(mchid)
                .privateKeyFromPath(privateKeyPath)
                .publicKeyFromPath(publicKeyPath)
                .publicKeyId(publicKeyId)
                .merchantSerialNumber(merchantSerialNumber)
                .apiV3Key(apiV3Key)
                .build();
        // 修改4：使用自动更新证书的验证器
        NotificationParser parser = new NotificationParser(config);
        log.info("parser：{}", JSON.toJSONString(parser));
        Map<String, String> map = new HashMap();
        Transaction transaction;
        try {
            // 合并解析操作，使用正确的通知类型
            transaction = parser.parse(requestParam, Transaction.class);
            log.info("验签成功回调参数：{}", JSON.toJSONString(transaction));
        } catch (ValidationException e) {
            log.error("验签失败详情{}", JSON.toJSONString(e));
            return null;
        }
        log.info("验签成功");
        //付款金额
        Integer total = transaction.getAmount().getTotal();
        String successTime = transaction.getSuccessTime();
        // 创建匹配的格式化器
        LocalDateTime dbTime = OffsetDateTime.parse(successTime).toLocalDateTime();
        //付款单号
        String transactionId = transaction.getTransactionId();
        //付款商家单号
        String outTradeNo = transaction.getOutTradeNo();
        //付款状态
        String tradeStateDesc = transaction.getTradeStateDesc();
        //付款方式
        log.info("付款商家单号：{}", outTradeNo);
        log.info("付款状态：{}", tradeStateDesc);
        if ("支付成功".equals(tradeStateDesc)) {
            ResultData resultData = orderRecordService.changeOrder(outTradeNo,transactionId,dbTime);
            if (resultData.isSuccess()) {
                Map<String, Object> resultMap = (Map<String, Object>) resultData.getData();
                Boolean isOk = (Boolean) resultMap.get("isOk");
                if (isOk){
                    Long customerId = Long.parseLong(resultMap.get("customerId").toString());
                    Long productId = Long.parseLong(resultMap.get("productId").toString());
                    Long orderRecordId=Long.parseLong(resultMap.get("orderRecordId").toString());
                    Boolean isChange=customerService.changeCustomer(customerId,productId,orderRecordId);
                    if (isChange){
                        return "success";
                    }else {
                        return "fail";
                    }
                }
            }
        }
        return null;
    }
    /*
     *统一查询支付接口
     */
    @Override
    public ResultData getPayStatus(String orderNum) {
        try {
            QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
            request.setMchid(mchid);
            request.setOutTradeNo(orderNum);
            Transaction transaction = service.queryOrderByOutTradeNo(request);
            log.info("微信统一查询支付接口查询订单:{}", JSON.toJSONString(transaction));
            log.info("微信统一查询支付接口查询订单状态:{}", transaction.getTradeStateDesc());
            if (transaction.getTradeStateDesc().equals("支付成功")){
                log.info("微信统一查询支付接口查询订单成功id:{}", transaction.getTransactionId());
                return ResultData.successData(true);
            }else {
                return ResultData.successData(false);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    /*
     *统一轮询查询支付接口
     */
    @Override
    public String getTaskPayStatus(String orderNum) {
        try {
            QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
            request.setMchid(mchid);
            request.setOutTradeNo(orderNum);
            Transaction transaction = service.queryOrderByOutTradeNo(request);
            log.info("微信统一轮询查询支付接口查询订单:{}", JSON.toJSONString(transaction));
            if (transaction.getTradeStateDesc().equals("支付成功")){
                return transaction.getTransactionId();
            }else {
                return "false";
            }
        } catch (Exception e) {
            return "false";
        }
    }
    /*
     *关闭订单
     */
    @Override
    public ResultData closeOrder(String orderNum) {
        CloseOrderRequest request = new CloseOrderRequest();
        request.setMchid(mchid);
        request.setOutTradeNo(orderNum);
        service.closeOrder(request);
        log.info("微信关闭订单:{}", orderNum);
        orderRecordService.orderExpire(orderNum);
        return ResultData.success();
    }
    /*
     *退款
     */
    @Override
    public ResultData refundWeixin(String orderNum,BigDecimal money){
        try {
            CreateRequest request = new CreateRequest();
            request.setOutTradeNo(orderNum);
            AmountReq orderAmount = new AmountReq();
            OrderRecord orderRecord=orderRecordService.getOrderRecordByOrderNum(orderNum);
            // 修改后的金额计算方式
            long total = orderRecord.getFee().multiply(new BigDecimal(100))
                    .setScale(0, RoundingMode.HALF_UP)
                    .longValue();
            long refund = money.multiply(new BigDecimal(100))
                    .setScale(0, RoundingMode.HALF_UP)
                    .longValue();
            request.setOutRefundNo(orderRecord.getThirdOrderNumber());
            orderAmount.setTotal(total);
            orderAmount.setRefund(refund);
            orderAmount.setCurrency("CNY");
            request.setAmount(orderAmount);
            Refund response= refundService.create(request);
            log.info("微信退款结果：{}", JSON.toJSONString(response));
            log.info("微信退款结果状态：{}", response.getStatus());
            if (response.getStatus().toString().equals("SUCCESS")||response.getStatus().toString().equals("PROCESSING")){
                log.info("微信退款成功");
                boolean refundSuccess = false;
                for (int i = 0; i < count; i++) {
                    Boolean queryResult = this.refundQuery(orderRecord.getThirdOrderNumber());
                    if (queryResult) {
                        refundSuccess = true;
                        break;
                    }
                    Thread.sleep(1000);
                }
                log.info("微信退款查询结果：{}", refundSuccess);
                if (refundSuccess){
                    //修改支付订单状态
                    boolean updateResult = update(new UpdateWrapper<OrderRecord>()
                            .eq("order_num", orderNum)
                            .set("order_status", PAY_STATUS_REFUND_SUCCESS));
                    if (!updateResult) {
                        log.error("订单状态更新失败，订单号：{}", orderNum);
                        return ResultData.failure("订单状态更新失败");
                    }
                    log.info("订单已成功关闭并更新状态，订单号：{}", orderNum);
                    if (orderRecord.getOrderRecordId()!=null){
                        ResultData resultData = orderRecordService.refund(orderRecord.getOrderRecordId(), money);
                        if (resultData.getCode()==200){
                            return ResultData.successMsg("订单已成功关闭");
                        }
                    }
                }
            }
        }catch (Exception e){
            log.error("关闭订单异常:{}", e);
        }
        return ResultData.failure("订单状态更新失败");
    }
    /*
     *退款查询
     */
    @Override
    public Boolean refundQuery(String orderNum){
        QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
        request.setOutRefundNo(orderNum);
        Refund response =refundService.queryByOutRefundNo(request);
        log.info("微信退款查询结果：{}", JSON.toJSONString(response));
        if (response.getStatus().toString().equals("SUCCESS")){
            return true;
        }
        return false;
    }
    @PostConstruct
    public void init() {
        // 初始化微信支付服务
        Config config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(mchid)
                        .privateKeyFromPath(privateKeyPath)
                        .merchantSerialNumber(merchantSerialNumber)
                        .apiV3Key(apiV3Key)
                        .build();
        this.service = new AppService.Builder().config(config).build();
        this.refundService= new RefundService.Builder().config(config).build();
        this.signer = config.createSigner();
    }
}
